#ifndef hpp_CPP_CircularMenu_CPP_hpp
#define hpp_CPP_CircularMenu_CPP_hpp

// We need juce declaration
#include "../../includes/includes.h"

namespace juce
{
    /** The circular menu is a popup menu with cool animation effect that tries to enhance ergonomy.
        All menu items are equidistant from the current mouse cursor position
        so reaching any item is shorted than traditional menus.
        Menu items are big (depending on the circular menu radius), so targetting them is easy too.
        Menu items also always keep a similar color so action selection becomes a "reflex"
       
        On the bad side, it's different from what user are used too, so it's up to you to choose what you prefer */
    class CircularMenu
    {
        // Type definition and enumeration
    private:
        /** This is a menu petal used to display a menu item */
        class MenuPetal  : public Component
        {
            // Members
        private:
            /** The petal path used for drawing */
            Path        petalPath;
            /** The menu icon (this is required, as this menu is graphic mainly) */
            Drawable &  icon;
            /** The menu ID */
            const int   itemID;
            /** The base menu color */
            Colour      baseColour;
            /** Do we have a sub menu ? */
            bool        withSubMenu;
            /** This petal surface angle in radian */
            float       surfaceAngle;
            /** This petal angle from X/Y axis */
            float       currentAngle;
            /** This petal pivot point */
            Point       pivot;   
            /** The current circle radius */
            float       petalRadius;
            /** This is the delta for the petal path's bounding box top left corner (this is used to speed up bounds checking) */
            Point       topLeftCorner;
            /** The image where the drawable was cached */
            Image *     iconImage;
            /** The icon top left corner (this is used to speed up painting too) */
            Point       iconTopLeftCorner;
            /** The component general offset */
            int         generalOffsetX, generalOffsetY;
            /** The item selection state */
            bool        isPreSelected;
           

            // Component interface
        public:
            /** Paint this petal */
            void paint (Graphics& g);
            /** Check if mouse is inside the petal */
            bool hitTest(int x, int y);
            /** Called when mouse enter this petal */
            void mouseEnter (const MouseEvent& e);
            /** Called when mouse leaves this petal */
            void mouseExit (const MouseEvent& e);
            /** Called when mouse button hasd been clicked on this petal */
            void mouseUp (const MouseEvent& e);


            //==============================================================================
            juce_UseDebuggingNewOperator

            // Our interface
        public:
            /** Rotate around the given pivot of the given angle
                @param x    The pivot's horizontal position relative to this component
                @param y    The pivot's vertical position relative to this component
                @param angle    The angle in radian */
            void rotateAround(const float x, const float y, const float angle);
            /** Set the circle radius */
            void setCircleRadius(const float radius);
            /** Resize to fit given circle radius */
            void resizeToFit(const float radius, const float finalAngle);
            /** Set the general offset */
            void setGeneralOffset(const int x, const int y);
            /** Check if this item is selected */
            bool isSelected();
            /** Select this item */
            void makeSelected(const bool shouldBeSelected = true);

            // Helpers
        private:
            /** Get the icon position and size */
            const Rectangle getIconBounds(const float angle = -1) const;

            // Construction and destruction
        public:
            /** Construct a menu petal to display with the given parameters
                @param nbPetal          The number of petal in this menu
                @param icon             A reference on a drawable used to display the item's icon
                @param itemID           The item ID 
                @param baseColour       Define the menu base colour
                @param hasSubMenu       Set to true if clicking this menu will display a submenu */
            MenuPetal (const int nbPetal, Drawable & icon, const int itemID, const Colour & baseColour, const bool hasSubMenu = false);
            /** The destructor */
            ~MenuPetal();

        private:
            /** Prevent copy constructor being generated */
            MenuPetal (const MenuPetal&);
            /** Prevent operator= being generated too */
            const MenuPetal& operator= (const MenuPetal&);
        };

        // Members
    private:
        /** The icons array */
        OwnedArray<Drawable>    icons;
        /** The item id */
        Array<int>              itemsId;
        /** The item title array */
        StringArray             itemTexts;

        // Interface
    public:
        /** Appends a new item for this menu to show.

            @param itemResultId     the number that will be returned from the show() method
                                    if the user picks this item. The value should never be
                                    zero, because that's used to indicate that the user didn't
                                    select anything.
            @param itemText         the text to show.
            @param isTicked         if true, the item will be shown with a tick next to it
            @param iconToUse        if this is non-zero, it should be an drawable that will be
                                    displayed in the menu petal. This method will take ownership of the drawable.

            @return true on success, false if the insertion couldn't be performed
            @see show
        */
        bool addItem (const int itemResultId,
                      Drawable* iconToUse,
                      const String& itemText
//                      const bool isTicked = false,
                      ) throw();

        /** Returns the number of items that the menu currently contains. */
        int getNumItems() const throw() { return itemsId.size(); }

        /** Displays the menu and waits for the user to pick something.

            This will display the menu modally, and return the ID of the item that the
            user picks. If they click somewhere off the menu to get rid of it without
            choosing anything, this will return 0.

            The current location of the mouse will be used as the position to show the
            menu - to explicitly set the menu's position, use showAt() instead. Depending
            on where this point is on the screen, the menu will appear above, below or
            to the side of the point.

            @param minimumRadius            a minimum radius for the menu, in pixels. It may be wider
                                            than this if some items are too long to fit.
            @see showAt
        */
        int show (const int minimumRadius);
        /** Displays the menu at a specific location.

            This is the same as show(), but uses a specific location (in global screen
            co-ordinates) rather than the current mouse position.

            @see show()
        */
        int showAt (const int screenX,
                    const int screenY,
                    const int minimumRadius);

        // Helpers
    private:
        /** Create the popup menu window */
        Component* createMenuComponent (const int x, const int y, const int w, const int h, ApplicationCommandManager** managerOfChosenCommand, Component* const componentAttachedTo) throw();
        friend struct CircularMenuWindow;
    };
}


#endif 